package com.lujianfei.netease_android_mvvm_kotlin.viewmodel

import android.content.res.Resources
import androidx.arch.core.executor.ArchTaskExecutor
import com.lujianfei.netease_android_mvvm_kotlin.App
import com.lujianfei.netease_android_mvvm_kotlin.adapter.MainAdapter
import com.lujianfei.netease_android_mvvm_kotlin.entity.DataBean
import com.lujianfei.netease_android_mvvm_kotlin.getOrAwaitValue
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.*
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.reflect.Whitebox


@RunWith(
    PowerMockRunner::class
)
// 涉及到对象的final,static,private成员类型调用时，需要在此声明一下
@PrepareForTest(MainViewModel::class, ArchTaskExecutor::class,App::class)
class MainViewModelTest {

    lateinit var mMainViewModel: MainViewModel
    lateinit var mArchTaskExecutor: ArchTaskExecutor

    @Before
    fun setup() {
        // 确保 ArchTaskExecutor.getInstance().isMainThread() 为 true，不然涉及到livedata的赋值操作会抛异常
        PowerMockito.mockStatic(ArchTaskExecutor::class.java)
        mArchTaskExecutor = mock(ArchTaskExecutor::class.java)
        `when`(ArchTaskExecutor.getInstance()).thenReturn(mArchTaskExecutor)
        `when`(ArchTaskExecutor.getInstance().isMainThread).thenReturn(true)

        // spy 一个viewModel，模拟真实操作逻辑
        mMainViewModel = PowerMockito.spy(MainViewModel())

        // mock 一个android 假资源，确保调用过程中涉及到资源调用的地方不会报空指针异常
        App.instance = PowerMockito.mock(App::class.java)
        PowerMockito.doReturn(PowerMockito.mock(Resources::class.java)).`when`(App.instance).resources
    }

    private fun initData() {
        // 数据初始化
        val mDataLists = ArrayList<DataBean>()
        val fieldDataLists = Whitebox.getField(mMainViewModel::class.java, "mDataLists")
        fieldDataLists.isAccessible = true
        for (index in 1..10) {
            mDataLists.add(
                DataBean(
                    id = index,
                    title = "title $index",
                    summary = "summary $index",
                    type = MainAdapter.TYPE_ITEM
                )
            )
        }
        fieldDataLists.set(mMainViewModel, mDataLists)
    }

    @Test
    fun should_setvalue_when_load_be_call() {
        mMainViewModel.load()
        // 测试livedata是否有赋值
        mMainViewModel.uiState.getOrAwaitValue {
            mMainViewModel.uiState.value?.let {
                it.datalist?.let {datalist->
                    assertTrue(datalist.isNotEmpty())
                } ?: assertTrue(false)
            }
        }
    }

    @Test
    fun should_return_empty_when_checkAll_and_clickDelete_be_call() {
        initData()
        val fieldDataLists = Whitebox.getField(mMainViewModel::class.java, "mDataLists")
        val  mDataLists = fieldDataLists.get(mMainViewModel) as ArrayList<DataBean>
        assertFalse(mDataLists.isEmpty())
        // 全选并删除
        mMainViewModel.setSelectAll(true)
        mMainViewModel.clickDelete()

        // 测试集合为空
        assertTrue(mDataLists.isEmpty())
    }

    @Test
    fun should_checked_when_clickItem_be_call() {
        initData()
        val fieldDataLists = Whitebox.getField(mMainViewModel::class.java, "mDataLists")
        val  mDataLists = fieldDataLists.get(mMainViewModel) as ArrayList<DataBean>
        val data = mDataLists[0]
        // 首次点击，data选中状态
        mMainViewModel.clickItem(data, true)

        PowerMockito.verifyPrivate(mMainViewModel, times(1))
            .invoke("emitUI", mDataLists, null, null, true, 0)

        // 测试选中状态
        assertTrue(data.checked)

        // 再次点击，data非选中状态
        mMainViewModel.clickItem(data, true)

        PowerMockito.verifyPrivate(mMainViewModel, times(1))
            .invoke("emitUI", mDataLists, null, null, true, 0)

        // 测试非选中状态
        assertFalse(data.checked)
    }

    @Test
    fun should_showtoast_when_clickItem_be_call() {
        initData()
        val fieldDataLists = Whitebox.getField(mMainViewModel::class.java, "mDataLists")
        val  mDataLists = fieldDataLists.get(mMainViewModel) as ArrayList<DataBean>
        val data = mDataLists[0]
        // 点击弹出Toast
        mMainViewModel.clickItem(data, false)

        // 测试是否调用了私有方法 emitUI
        PowerMockito.verifyPrivate(mMainViewModel, times(1))
            .invoke("emitUI", null, "${data.title} 被点击", null, null, null)
    }
}